// MidiReceiveExample.pde
// http://timothytwillman.com/?page_id=240

// This sketch turns on the LED at D13 when any "NOTE ON" message is received.
//  It turns the LED off when any "NOTE OFF" message is received.
//
// (note that NOTE ON's with velocity = 0 are actually NOTE OFF's, and are
//  treated as such)
//
// It's necessary to subclass Midi in order to handle receiving messages.  If
//  you're only sending data, see MidiSendExample, which is a bit simpler.
//
// If you're both sending AND receiving you'll need to subclass like this,
//  but only for receive functions.
//

#include "Midi.h"

#define POWERPIN  4             // LED  #1
#define SIGNALPIN  3             // LED #2


#include "WProgram.h"
void setup();
void loop();
void write_value(uint16_t sample);
void playNote(int incomingByte);
void noteOff();
int oldnote;

// PIN FOR LED

// PINs for DAC
#define DATAOUT 11//MOSI
#define DATAIN 12//MISO - not used, but part of builtin SPI
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

// To use the Midi class for receiving Midi messages, you need to subclass it.
//  If you're a C++ person this makes sense; if not, just follow the example
//  functions below.
//
// Basically, MyMidi here can do anything Midi can do -- it just has the ability
//  to easily change what the functions do when different message types are received.
//
class MyMidi : public Midi {
  public:
  
  // Need this to compile; it just hands things off to the Midi class.
  MyMidi(HardwareSerial &s) : Midi(s) {}
  
  void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    if ( note != oldnote) 
      noteOff();
    
    playNote(note);

    digitalWrite(SIGNALPIN, HIGH);
    /*
    lcd.home();
    lcd.print("NOTE ON  :");
    lcd.print(note);
    lcd.print("   ");
   */
    
    oldnote = note;
  }

  void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity)
  {
    if ( note == oldnote) 
       noteOff();

    digitalWrite(SIGNALPIN, LOW);
    /*
    lcd.setCursor(0,1);
    lcd.print("     OFF :");
    lcd.print(note);
    lcd.print("   ");
    */
  }
  
  /* You can define any of these functions and they will be called when the
     matching message type is received.  Otherwise those types of Midi messages
     are just ignored.

    For C++ folks: these are all declared virtual in the base class

    void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity);
    void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value);
    void handleProgramChange(unsigned int channel, unsigned int program);
    void handleAfterTouch(unsigned int channel, unsigned int velocity);
    void handlePitchChange(unsigned int pitch);
    void handleSongPosition(unsigned int position);
    void handleSongSelect(unsigned int song);
    void handleRuneRequest(void);
    void handleSync(void);
    void handleStart(void);
    void handleContinue(void);
    void handleStop(void);
    void handleActiveSense(void);
    void handleReset(void);
*/
};

// Create an instance of the MyMidi class.
MyMidi midi(Serial);


void setup()
{
  // initialize DAC
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device
  

  /* ======== FOR DAC
  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  ==================== */
  delay(10);

  pinMode(POWERPIN, OUTPUT);
  pinMode(SIGNALPIN, OUTPUT);
  
  digitalWrite(POWERPIN, HIGH);




  // initialize LCD
  /*
  lcd.begin();
  lcd.print("MIDI SIGNAL CHECK ");
  lcd.setCursor(0,1);
  lcd.print("  START");
  delay(1000);
  lcd.clear();
  */

  // This causes the midi object to listen to ALL Midi channels.  If a number
  //  from 1-16 is passed, messages will be filtered so that any messages to
  //  channels other than the given one will be ignored.
  //
  // Note that you can pass a second parameter as a baud rate, if you're doing
  //  Midi protocol but using some other communication method (e.g. sending
  //  Midi data from Max/MSP using the standard Arduino USB connection, you
  //  can set the baud rate to something more standard and use the regular
  //  Max serial object)
  midi.begin(0);
}


void loop()
{
  // Must be called every time through loop() IF dealing with incoming MIDI --
  //  if you're just sending MIDI out, you don't need to use poll().
  //
  // Make sure other code doesn't take too long to process or serial data
  //  can get backed up (and you can end up with obnoxious latency that ears
  //  don't like).
  //
  // The poll function will cause the midi code to suck data from the serial 
  //  port and process it, and call any functions that are defined for handling
  //  midi messages.
  midi.poll();
}

void write_value(uint16_t sample)
{
  return; // FOR DEBUG USE ONLY
  uint8_t dacSPI0 = 0;
  uint8_t dacSPI1 = 0;
  dacSPI0 = (sample >> 8) & 0x00FF;
  dacSPI0 |= 0x10;
  dacSPI1 = sample & 0x00FF;
  digitalWrite(SLAVESELECT,LOW);
  SPDR = dacSPI0;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  
  SPDR = dacSPI1;
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };  
  digitalWrite(SLAVESELECT,HIGH);
  delay(5);
}

void playNote(int incomingByte)
{
   
  int diff = 48 - incomingByte;
  diff *= 12;
  write_value (1125 - diff);
  // 1270 C4 60
  // 1125 C3 48
  // 980  C2 36    
  // 835  C1 24 
  // 690  C0 12      
}
void noteOff()
{
  write_value(0);
}

int main(void)
{
	init();

	setup();
    
	for (;;)
		loop();
        
	return 0;
}

